#include "GLBillBoard.h"
#include "RenderController.h"
#include "common.h"
#include <QDebug>
#include <QOpenGLPixelTransferOptions>
#include <QPainter>
#include <QPen>
#include <QTextOption>
static const int cVertexLocation			= 0;
static const int cMultiTextureCoordLocation = 1;

struct GLBillBoardPrivate
{
	QPoint	 mPos;					// 左上角坐标，相对背景大图
	QSize	 mSize;					// 尺寸, 像素，相对OpenGL窗口
	QPoint	 mWindowPosTopLeft;		// 左上角坐标，相对OpenGL窗口
	QPoint	 mWindowPosBottomRight; // 右下角坐标，相对OpenGL窗口
	bool	 mPressed = false;		// 是否按下
	QPoint	 mPressedWindowPos;		// 按下时的窗口坐标
	bool	 mIsSelect = false;		// 是否被选中,控制高亮
	bool	 mIsExpand = true;
	QSize	 mExpandSize;
	QString	 mText;
	Callback mGeometryChangedCall = {};
	Callback mIsSelectedChangedCall = {};
	Callback mIsExpandChangedCall	= {};

	QMatrix4x4 mCompMat;
};

GLBillBoard::GLBillBoard()
	: d(new GLBillBoardPrivate)
{
}
GLBillBoard::~GLBillBoard()
{
	delete d;
}
void GLBillBoard::setGeometryChangedCallback(const Callback& call)
{
	d->mGeometryChangedCall = call;
}
void GLBillBoard::setIsSelectedChangedCallback(const Callback& call)
{
	d->mIsSelectedChangedCall = call;
}
void GLBillBoard::setIsExpandChangedCallback(const Callback& call)
{
	d->mIsExpandChangedCall = call;
}

QVector<QVector3D> GLBillBoard::getVertices() const
{
	QVector<QVector3D> ret;
	auto			   backSize	  = gController->backgroundSize();
	auto			   windowSize = gController->viewSize() * qApp->devicePixelRatio();
	auto			   scale	  = gController->scale();

	d->mWindowPosTopLeft = backgroundPosToWindowPos(pos(), backSize, windowSize, scale);
	auto topLeft		 = posNormal(d->mWindowPosTopLeft, windowSize);

	d->mWindowPosBottomRight = QPoint(d->mWindowPosTopLeft.x() + size().width(), d->mWindowPosTopLeft.y() + size().height());
	auto bottomRight		 = posNormal(d->mWindowPosBottomRight, windowSize);

	qreal left	 = topLeft.x();
	qreal right	 = bottomRight.x();
	qreal top	 = topLeft.y();
	qreal bottom = bottomRight.y();
	ret << QVector3D(left, bottom, 0.0);
	ret << QVector3D(left, top, 0.0);
	ret << QVector3D(right, top, 0.0);
	ret << QVector3D(right, bottom, 0.0);
	return ret;
}
bool GLBillBoard::containsPos(const QPoint& windowPos) const
{
	//	qWarning() << "containsPos" << windowPos << d->mWindowPosTopLeft << d->mWindowPosBottomRight;
	return inRange(windowPos.x(), d->mWindowPosTopLeft.x(), d->mWindowPosBottomRight.x()) &&
		inRange(windowPos.y(), d->mWindowPosTopLeft.y(), d->mWindowPosBottomRight.y());
}
bool GLBillBoard::onPress(const QPoint& pos)
{
	/*    if (!isExpand())
		{
			qDebug()<<"!isExpand";
			return false;
		}*/
	if (containsPos(pos))
	{
		// qDebug()<<"containsPos "<< d->mPressed;
		if (!d->mPressed)
		{
			d->mPressed			 = true;
			d->mPressedWindowPos = pos - d->mWindowPosTopLeft;
			//			qWarning() << "pressed" << d->mPressedWindowPos;
			return true;
		}
	}
	return false;
}

bool GLBillBoard::onMove(const QPoint& pos)
{
	/*-if (!isExpand())
	{
		return false;
	}*/
	if (d->mPressed)
	{
		auto newTopLeftPos = pos - d->mPressedWindowPos;
		auto backPos	   = windowPosToBackground(newTopLeftPos, gController->backgroundSize(), gController->viewSize(), gController->scale());
		//		qWarning() << "move" << d->mPressedWindowPos;
		setPos(backPos);
		return true;
	}
	return false;
}

bool GLBillBoard::onRelease(const QPoint& pos)
{
	if (containsPos(pos))
	{
		if (d->mPressed)
		{
			d->mPressed = false;
			return true;
		}
	}
	return false;
}

bool GLBillBoard::onDoubleClicked(const QPoint& pos)
{
	if (containsPos(pos))
	{
		if (isExpand())
		{
			d->mExpandSize = d->mSize;
			setSize(QSize(d->mSize.width(), 36));
		}
		else
		{
			setSize(d->mExpandSize);
		}
		setIsExpand(!isExpand());
		return true;
	}
	return false;
}

void GLBillBoard::setPos(const QPoint& pos, bool notify)
{
	if (d->mPos != pos)
	{
		d->mPos = pos;
		updateWindowPos();
		if (notify)
		{
			if (d->mGeometryChangedCall)
			{
				d->mGeometryChangedCall();
			}
		}
	}
}
const QPoint& GLBillBoard::pos() const
{
	return d->mPos;
}
void GLBillBoard::setSize(const QSize& size, bool notify)
{
	if (d->mSize != size)
	{
		d->mSize = size;
		updateWindowPos();
		if (notify)
		{
			if (d->mGeometryChangedCall)
			{
				d->mGeometryChangedCall();
			}
		}
	}
}
const QSize& GLBillBoard::size() const
{
	return d->mSize;
}

void GLBillBoard::setIsSelected(bool v, bool notify)
{
	if (d->mIsSelect != v)
	{
		d->mIsSelect = v;
		updateWindowPos();
		if (notify)
		{
			if (d->mIsSelectedChangedCall)
			{
				d->mIsSelectedChangedCall();
			}
		}
	}
}
bool GLBillBoard::isSelected() const
{
	return d->mIsSelect;
}

QRect GLBillBoard::windowRect() const
{
	return QRect(d->mWindowPosTopLeft, d->mWindowPosBottomRight);
}
void GLBillBoard::setIsExpand(bool v, bool notify)
{
	if (d->mIsExpand != v)
	{
		d->mIsExpand = v;
		updateWindowPos();
		if (notify)
		{
			if (d->mIsExpandChangedCall)
			{
				d->mIsExpandChangedCall();
			}
		}
	}
}
bool GLBillBoard::isExpand() const
{
	return d->mIsExpand;
}
void GLBillBoard::updateWindowPos()
{
	QVector<QVector3D> ret;
	auto			   backSize	  = gController->backgroundSize();
	auto			   windowSize = gController->viewSize() * qApp->devicePixelRatio();
	auto			   scale	  = gController->scale();

	d->mWindowPosTopLeft = backgroundPosToWindowPos(pos(), backSize, windowSize, scale);

	d->mWindowPosBottomRight = QPoint(d->mWindowPosTopLeft.x() + size().width(), d->mWindowPosTopLeft.y() + size().height());
}
const QMatrix4x4& GLBillBoard::compMat() const
{
	return d->mCompMat;
}
void GLBillBoard::setCompMat(const QMatrix4x4& mat)
{
	d->mCompMat = mat;
}
